home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Communication
/
Weather
/
Source
/
state.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-14
|
8KB
|
347 lines
/*
* State machine and menu abstraction.
* The idea is to keep as much of the hookup dialog
* as possible in a text file, so that menus and hookup protocols
* are easy to change here or in other apps.
* It has grown a few warts.
*
* M. J. Hawley
* mike@media-lab.mit.edu
* Copyright (c) November 1991, MIT Media Laboratory.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libc.h>
#include "util.h"
#include "state.h"
#include "StormFunc.h"
#define MENU 1
SType lastType = Plain;
static char *getStr(char *s, char *t) {
char end = ' ';
*t = '\0';
s = skipsp(s);
lastType = Plain;
switch (*s){
case '/': lastType = Pattern;
Case '+': lastType = Status; s++;
Case '!': lastType = CmdS; s++;
Case ',': lastType = FlushS; s++;
Case '=': lastType = Goto; s = skipsp(s+2);
}
if (*s=='/' || *s == '"') end = *s++;
while (*s && !(*s == end || (end==' ' && *s == '\t'))){
*t = *s++;
if (*t == '\\') switch (*s){
case 'n': *t = '\n'; s++;
Case 't': *t = '\t'; s++;
Case 'b': *t = '\b'; s++;
Default : *t = *s; s++;
}
t++;
}
*t = '\0';
if (*s && *s != ' ' && *s != '\t') ++s;
if (*s) s = skipsp(s);
return s;
}
static State *
newMenu(char *s) {
State *S = Alloc(State);
char n[1024], first[1024], last[1024], label[1024];
s = skipsp(skipsp(s)+4);
sscanf(s,"%[^:]",n);
s = skipsp(index(s,':')+1);
s = getStr(s,first);
s = getStr(s,last);
s = getStr(s,label);
S->name = save(n);
S->label = save(label);
S->first = save(first);
S->last = save(last);
S->type = MENU;
return S;
}
static State *
newState(char *s) {
State *S = Alloc(State);
S->name = save(s);
return S;
}
static String *
addStr(String *s, char *t) {
String *start = s, *n = Alloc(String);
char *p;
p = n->s = save(t);
if (*p=='/' && (p = index(p+1,'/'))){
while (p[-1]=='\\') p = index(p+1,'/');
if (p) *p = '\0';
}
if (!s) return n;
while (s->next) s = s->next;
s->next = n;
return start;
}
static void stripq(char *s) {
if (*s == '\"'){
strcpy(s,s+1);
if (s = rindex(s,'\"')) *s = '\0';
}
}
static void
addMenu(State *S, char *s) {
char send[1024], get[1024], label[1024];
MenuItem *m = Alloc(MenuItem), *t;
s = getStr(s,send); m->send = save(send);
s = getStr(s,get); m->get = save(get);
skipsp(s); strcpy(label,s); stripnl(label); stripq(label); m->label = save(label);
for (t=S->m; t && t->next; t = t->next) ;
if (t) t->next = m; else S->m = m;
}
static void
addString(State *S, char *s) {
stripnl(s=skipsp(s));
S->l = addStr(S->l,s);
}
#define MaxS 256
static State *ST[MaxS];
static int NS = 0;
static void
readState(FILE *f) {
char s[1024], n[1024];
State *S = (State *)0;
while (fgets(s,sizeof s,f)){
stripcomment(s);
if (blank(s)) continue;
if (strncmp(s,"Menu",4)==0){
S = newMenu(s);
ST[NS++] = S;
} else
if (match(s,"[a-zA-Z]*:")){
sscanf(s,"%[^:]",n);
S = newState(n);
ST[NS++] = S;
} else
if (S){
if (S->type == MENU) addMenu(S,s); else
addString(S,s);
}
}
}
State*
state(char *s) {
int i;
s = skipsp(s);
for (i=0;i<NS;i++)
if (strcmp(s,ST[i]->name)==0) return ST[i];
return (State *)0;
}
/*
static char *str(char *s) { return s? s : ""; }
static void
printState(State *s) {
if (!s) {
printf("huh?\n");
return;
}
printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
}
*/
void
ReadState(char *s) {
FILE *f;
if (!NS){
f = fopen(s,"r");
if (f) readState(f), fclose(f);
}
setState("Attach");
setMenu("Main");
}
State *curState = (State *)0;
void
setState(char *s) {
curState = state(s);
if (strcmp(s,"Detach")==0) logout();
if (strcmp(s,"Ready")==0) fetchReports();
}
static void
execute(char *s) {
char t[1024];
if (s[0]=='/') s += strlen(s)+1;
while ((s=getStr(s,t)) && *t) switch (lastType){
case CmdS: Command(t);
Case Status : message(t);
Case Plain : if (!state(t)) Put("%s",t);
Case FlushS : Flush(t);
Case Goto : setState(t);
Case Pattern: break;
Case Pause : break;
}
}
void
execState(State *s, char *t) {
String *l;
if (!s) s = curState;
if (!s || !s->l) return;
for (l=s->l; l; l=l->next){
if (l->s[0]!='/') execute(l->s);
else
if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
}
}
void
runState(char *s) {
execState(curState,s);
}
int numItem(char *s) {
int i = 0;
State *S = state(s);
MenuItem *m;
if (!S) return 0;
for (m=S->m; m; m=m->next) i++;
return i;
}
State *curMenu;
void setMenu(char *s) { curMenu = state(s); }
MenuItem *
curMenuItem(int n) {
MenuItem *m;
if (!curMenu) return (MenuItem *)0;
for (m=curMenu->m; m && n-->0; m = m->next) ;
return m;
}
static int valid(MenuItem *m) {
MenuItem *t;
if (!curMenu) return 0;
for (t=curMenu->m; t; t=t->next)
if (t==m) return 1;
return 0;
}
char *getLabel(MenuItem *m) { return valid(m)? m->label : ""; }
char *getSend(MenuItem *m) { return valid(m)? m->send : ""; }
char *getGet(MenuItem *m) { return valid(m)? m->get : ""; }
char *curMenuFirst(void) { return curMenu? curMenu->first : "**nada**"; }
char *curMenuLast(void) { return curMenu? curMenu->last : "**nada**"; }
char *
getReport(char *buf) {
char *p = buf+1;
int starting = 1;
strcpy(buf,"\n");
while (pgets(p,1024) && !strindex(p,curMenuFirst())){
if (Verbose) printf("+%s",p);
if (starting && strlen(p)<=5)
;
else
if (strindex(p,"Enter 3-letter") || strindex(p,"Enter 2-letter")
|| strindex(p,"Selection:"))
;
else
if (strindex(p,"ress return") || strindex(p,"ress Return"))
Put("\n");
else
starting = 0, p += strlen(p);
}
*p = '\0';
if (curMenu) Flush(curMenuLast());
return buf;
}
MenuItem *
menuFor(char *label, char *name) {
int i;
MenuItem *m;
*name = '\0';
for (i=0;i<NS;i++){
if (ST[i]->type == MENU){
for (m=ST[i]->m;m;m=m->next)
if (strcmp(label,m->label)==0){
strcpy(name,ST[i]->name);
return m;
}
}
}
return (MenuItem *)0;
}
#define hackflush() sleep(1); while (pgets(hack,1024) && !strindex(hack,curMenuLast())) if (Verbose) printf("+%s",hack)
void
fetchReport(char *label, char *buf) {
char menu[256];
char hack[1024];
MenuItem *m = menuFor(label,menu);
*buf = '\0';
if (!m) return;
{
State *s = state("Main");
MenuItem *t = s->m;
for (;t && strcmp(t->get,menu);t=t->next) ;
if (t)
Put("%s",t->send);
}
setMenu(menu); hackflush();
Put("%s",m->send);
if (strcmp(menu,"Main")==0) pgets(hack,1024);
getReport(buf);
if (strcmp(curMenu->name,"Main")){
Put("m\n"), setMenu("Main");
hackflush();
} else
hackflush();
}
/*
void print(void){
int i;
for (i=0;i<NS;i++) printState(ST[i]);
}
int main(main){
char s[1024];
ReadState("states");
print();
setState("Attach");
*s = '\0';
do { runState(s); } while (gets(s));
}
*/